﻿namespace QuickMail.View.Windows
{
    using System;
    using System.Globalization;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Forms;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;

    using MahApps.Metro.Controls.Dialogs;
    using QuickMail.BusinessLogic;
    using QuickMail.DataModels;
    using QuickMail.Properties;
    using QuickMail.View.Controls;
    using QuickMail.ViewModels;

    /// <summary>
    /// The main window.
    /// </summary>
    public partial class MainWindow
    {
        #region Fields and properties

        private enum CurrentConnectionStatus
        {
            Wait = 0,
            Configure = 1,
            Success = 2,
            Error = 3
        }

        private readonly TestConnectionController _tcController = new TestConnectionController();
        private readonly MailsController _mailsController = new MailsController();
        private readonly MessageControl _messageControl;
        private readonly LettersControl _lettersControl;

        private int _messageIndex;
        private LoginDialogData _loginDialogData;
        private ProgressDialogController _progressDialogController;
        private CurrentConnectionStatus _ccs = CurrentConnectionStatus.Wait;

        private static readonly RoutedCommand _backCommand = new RoutedCommand("Back", typeof(MessageControl));
        private static readonly RoutedCommand _nextMessageCommand = new RoutedCommand("NextMessage", typeof(MessageControl));
        private static readonly RoutedCommand _previousMessageCommand = new RoutedCommand("PreviousMessage", typeof(MessageControl));
        private static readonly RoutedCommand _deleteMessageCommand = new RoutedCommand("DeleteMessage", typeof(MessageControl));
        //private static readonly RoutedCommand _readLetterCommand = new RoutedCommand("ReadLetter", typeof(QmBalloon));

        public static RoutedCommand BackCommand
        {
            get
            {
                return _backCommand;
            }
        }

        public static RoutedCommand NextMessageCommand
        {
            get
            {
                return _nextMessageCommand;
            }
        }

        public static RoutedCommand PreviousMessageCommand
        {
            get
            {
                return _previousMessageCommand;
            }
        }

        public static RoutedCommand DeleteMessageCommand
        {
            get
            {
                return _deleteMessageCommand;
            }
        }

        //public static RoutedCommand ReadLetterCommand
        //{
        //    get
        //    {
        //        return _readLetterCommand;
        //    }
        //}

        #endregion //Fields and properties

        /// <summary>
        /// The constructor of the main window
        /// </summary>
        public MainWindow()
        {
            CheckingFirstStart();
            InitializeComponent();
            SetCurrentTranslate();

            CommandBindings.Add(new CommandBinding(BackCommand, OnBackCommandExecute));
            CommandBindings.Add(new CommandBinding(NextMessageCommand, OnNextMessageExecute));
            CommandBindings.Add(new CommandBinding(PreviousMessageCommand, OnPreviousMessageExecute));
            CommandBindings.Add(new CommandBinding(DeleteMessageCommand, OnDeleteMessageExecute));
            //CommandBindings.Add(new CommandBinding(ReadLetterCommand, OnReadLetterExecute));

            _messageControl = new MessageControl();
            _lettersControl = new LettersControl();
            _lettersControl.MessageClicked += LettersControlOnMessageClicked;

            DataPresenter.Content = _lettersControl;

            MainRulesControl.RulesTreeView.SelectedItemChanged += RulesTreeView_SelectedItemChanged;
            MainRulesControl.Load();

            _mailsController.LetterSended += MailsControllerOnLetterSended;
            _mailsController.LetterNotSended += MailsControllerOnLetterNotSended;
            _mailsController.LetterReceived += MailsControllerOnLetterReceived;
            // ReSharper disable once RedundantThisQualifier
            this.Loaded += OnLoaded;

            if (Settings.Default.CheckFoldersPeriod < 30000)
            {
                Settings.Default.CheckFoldersPeriod = 30000;
                Settings.Default.Save();
            }
        }

        /// <summary>
        /// Sets the translate in accordance with the system language.
        /// </summary>
        private void CheckingFirstStart()
        {
            StaticFields.Lang = HelpWorker.GetLocalisation(AppDomain.CurrentDomain.BaseDirectory + @"Languages\English.xml");
            if (Settings.Default.IsFirstStart)
            {
                string langPath = AppDomain.CurrentDomain.BaseDirectory + @"Languages\English.xml";
                switch (CultureInfo.CurrentCulture.TwoLetterISOLanguageName)
                {
                    case "ru":
                        langPath = AppDomain.CurrentDomain.BaseDirectory + @"Languages\Russian.xml";
                        break;
                    case "de":
                        langPath = AppDomain.CurrentDomain.BaseDirectory + @"Languages\Deutsch.xml";
                        break;
                }

                StaticFields.Lang = HelpWorker.GetLocalisation(langPath);
                Settings.Default.LanguagePath = langPath;
                Settings.Default.IsFirstStart = false;
                Settings.Default.Save();
            }
            else
            {
                StaticFields.Lang = HelpWorker.GetLocalisation(Settings.Default.LanguagePath);
            }   
        }

        /// <summary>
        /// Sets the current translation for form elements.
        /// </summary>
        private void SetCurrentTranslate()
        {
            QuickMailWindow.Title = StaticFields.Lang.MainWindow.Title;
            ConnectSettingsButton.ToolTip = StaticFields.Lang.MainWindow.ConnectSettings;
            CommonSettingsButton.ToolTip = StaticFields.Lang.MainWindow.CommonSettings;
            AboutButton.ToolTip = StaticFields.Lang.MainWindow.About;
            RulesGroupBox.Header = StaticFields.Lang.MainWindow.RulesForFolders;
            ListOfLettersGroupBox.Header = StaticFields.Lang.MainWindow.ListOfMails;

            switch (_ccs)
            {
                case CurrentConnectionStatus.Wait:
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.WaitConnect;
                    break;
                case CurrentConnectionStatus.Configure:
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.ConfigureConnect;
                    break;
                case CurrentConnectionStatus.Success:
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.SuccessConnect;
                    break;
                case CurrentConnectionStatus.Error:
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.ErrorConnect;
                    break;
            }
        }

        /// <summary>
        /// Sets the connect status icon and text.
        /// </summary>
        void SetConnectionStatus(CurrentConnectionStatus status)
        {
            switch (status)
            {
                case CurrentConnectionStatus.Wait:
                    StatusImage.Source = new BitmapImage(new Uri
                        ("pack://application:,,,/QuickMail;component/Resources/disconnected-32.png"));
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.WaitConnect;
                    break;

                case CurrentConnectionStatus.Configure:
                    StatusImage.Source = new BitmapImage(new Uri
                        ("pack://application:,,,/QuickMail;component/Resources/disconnected2-32.png"));
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.ConfigureConnect;
                    break;

                case CurrentConnectionStatus.Success:
                    StatusImage.Source = new BitmapImage(new Uri
                        ("pack://application:,,,/QuickMail;component/Resources/connected2-32.png"));
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.SuccessConnect;
                    break;

                case CurrentConnectionStatus.Error:
                    StatusImage.Source = new BitmapImage(new Uri
                        ("pack://application:,,,/QuickMail;component/Resources/disconnected2-32.png"));
                    StatusTextBlock.Text = StaticFields.Lang.MainWindow.Status.ErrorConnect;
                    break;
            }

            _ccs = status;
        }

        /// <summary>
        /// Handler complete the connection test.
        /// </summary>
        void OnTestConnectionComplete(bool incomingResult, bool outgoingResult)
        {
            _tcController.TestConnectionComplete -= OnTestConnectionComplete;
            if (incomingResult && outgoingResult)
            {
                SetConnectionStatus(CurrentConnectionStatus.Success);
                _mailsController.RunCheckMails(MainRulesControl.RuleVms);
            }
            else
            {
                SetConnectionStatus(CurrentConnectionStatus.Error);
            }
        }

        #region Interface events

        /// <summary>
        /// Runs the connection test after loading windows.
        /// </summary>
        private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            if (_tcController.CheckConnectSettings())
            {
                _tcController.TestConnectionComplete += OnTestConnectionComplete;
                _tcController.RunTestConntection();
            }
            else
            {
                ShowAuthorizationDialog();
                SetConnectionStatus(CurrentConnectionStatus.Configure);
            }
        }

        /// <summary>
        /// Shows dialog of authorization
        /// </summary>
        private async void ShowAuthorizationDialog()
        {
            MetroDialogOptions.ColorScheme = MetroDialogColorScheme.Accented;
            MessageDialogResult result = await ShowWelcomeDialog();

            if (result == MessageDialogResult.Negative)
                return;

            do
            {
                _loginDialogData = null;
                _loginDialogData = await this.ShowLoginAsync(StaticFields.Lang.WelcomeDialog.Title, 
                    StaticFields.Lang.WelcomeDialog.Configure,
                    new LoginDialogSettings
                    {
                        ColorScheme = MetroDialogOptions.ColorScheme,
                        UsernameWatermark = StaticFields.Lang.WelcomeDialog.EmailWatermark,
                        PasswordWatermark = StaticFields.Lang.WelcomeDialog.PasswordWatermark
                    });

            }
            while (!CheckingFields());

            if (_loginDialogData != null)
            {
                _progressDialogController = await this.ShowProgressAsync
                    (StaticFields.Lang.WelcomeDialog.Wait, StaticFields.Lang.WelcomeDialog.ConfiguringTheConnection);
                ConnectionSetupWorker.DetectServer(string.Empty, _loginDialogData.Username, _loginDialogData.Password);

                _tcController.TestConnectionComplete += OnTestConnectionCompleteAsync;
                _tcController.RunTestConntection();
            }
        }

        /// <summary>
        /// Shows message of tests connection result
        /// </summary>
        private async void OnTestConnectionCompleteAsync(bool incomingResult, bool outgoingResult)
        {
            await _progressDialogController.CloseAsync();
            _tcController.TestConnectionComplete -= OnTestConnectionComplete;
            if (incomingResult && outgoingResult)
            {
                SetConnectionStatus(CurrentConnectionStatus.Success);
                _mailsController.RunCheckMails(MainRulesControl.RuleVms);

                await this.ShowMessageAsync
                    (StaticFields.Lang.WelcomeDialog.Congratulations, StaticFields.Lang.WelcomeDialog.SuccessComplete);
                _mailsController.RunCheckMails(MainRulesControl.RuleVms);
            }
            else
            {
                SetConnectionStatus(CurrentConnectionStatus.Error);
                await this.ShowMessageAsync
                    (StaticFields.Lang.WelcomeDialog.Sorry, StaticFields.Lang.WelcomeDialog.FailureComplete);
            }
        }

        /// <summary>
        /// Checks the correctness of input fields.
        /// </summary>
        /// <returns>true - correct, false - incorrect</returns>
        private bool CheckingFields()
        {
            if (_loginDialogData == null)
                return true;

            if (_loginDialogData.Username == null || string.IsNullOrEmpty(_loginDialogData.Username.Trim()) ||
                !HelpWorker.IsValidMail(_loginDialogData.Username.Trim()))
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Shows an introductory message.
        /// </summary>
        /// <returns>Dialog result</returns>
        private async Task<MessageDialogResult> ShowWelcomeDialog()
        {
            var mySettings = new MetroDialogSettings
            {
                AffirmativeButtonText = StaticFields.Lang.WelcomeDialog.Affirmative,
                NegativeButtonText = StaticFields.Lang.WelcomeDialog.Negative,
                ColorScheme = MetroDialogOptions.ColorScheme
            };

            return await this.ShowMessageAsync(StaticFields.Lang.WelcomeDialog.Title,
                StaticFields.Lang.WelcomeDialog.QuestionConnectionSettings,
                MessageDialogStyle.AffirmativeAndNegative, mySettings);
        }

        /// <summary>
        /// Shows the "Connect settings window"
        /// </summary>
        private void ConnectSettings_OnClick(object sender, RoutedEventArgs e)
        {
            _mailsController.StopCheckMails();
            var csw = new ConnectSettingsWindow(_tcController) { Owner = this };
            if (csw.ShowDialog() == true)
            {
                SetConnectionStatus(CurrentConnectionStatus.Wait);
                _tcController.TestConnectionComplete += OnTestConnectionComplete;
                _tcController.RunTestConntection();
            }
        }

        /// <summary>
        /// Shows the "Common settings window"
        /// </summary>
        private void CommonSettings_OnClick(object sender, RoutedEventArgs e)
        {
            var csw = new CommonSettingsWindow { Owner = this };
            if (csw.ShowDialog() == true)
            {
                StaticFields.Lang = XmlWorker.DeserializeLang(Settings.Default.LanguagePath);

                SetCurrentTranslate();
                _lettersControl.SetCurrentTranslate();
                MainRulesControl.SetCurrentTranslate();
            }
        }

        /// <summary>
        /// Shows the window "About".
        /// </summary>
        private void About_OnClick(object sender, RoutedEventArgs e)
        {
            var aboutWindow = new AboutWindow { Owner = this };
            aboutWindow.ShowDialog();

            //GC.Collect();
        }

        /// <summary>
        /// Seeking letters by changing the query.
        /// </summary>
        private void SearchTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
        {
            if (string.IsNullOrEmpty(SearchTextBox.Text.Trim()))
                return;

            _lettersControl.Search(SearchTextBox.Text.Trim());
            DataPresenter.Content = _lettersControl;
        }

        /// <summary>
        /// Seeking letters when you click on the search button.
        /// </summary>
        private void Search_OnClick(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(SearchTextBox.Text.Trim()))
                return;

            _lettersControl.Search(SearchTextBox.Text.Trim());
            DataPresenter.Content = _lettersControl;
        }

        /// <summary>
        /// Minimizes the window to the system tray.
        /// </summary>
        protected override void OnStateChanged(EventArgs e)
        {
            if (WindowState == WindowState.Minimized)
            {
                // ReSharper disable once RedundantThisQualifier
                this.Hide();
            }

            base.OnStateChanged(e);
        }

        /// <summary>
        /// Change selection rule.
        /// </summary>
        private void RulesTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            var selectedRule = MainRulesControl.RulesTreeView.SelectedItem as RuleVm;
            if (selectedRule == null)
                return;

            _lettersControl.Load(selectedRule.Id);
            DataPresenter.Content = _lettersControl;
        }

        /// <summary>
        /// Out of control with letter.
        /// </summary>
        private void OnBackCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            DataPresenter.Content = _lettersControl;
        }

        /// <summary>
        /// Shows the next letter.
        /// </summary>
        private void OnNextMessageExecute(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            _messageIndex++;
            _messageControl.PreviousButton.IsEnabled = _messageIndex != 0;
            _messageControl.NextButton.IsEnabled = _messageIndex != (_lettersControl.CurrentLetters.Count - 1);
            _messageControl.Load(_lettersControl.CurrentLetters[_messageIndex]);
        }

        /// <summary>
        /// Shows the previous letter.
        /// </summary>
        private void OnPreviousMessageExecute(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            _messageIndex--;
            _messageControl.PreviousButton.IsEnabled = _messageIndex != 0;
            _messageControl.NextButton.IsEnabled = _messageIndex != (_lettersControl.CurrentLetters.Count - 1);
            _messageControl.Load(_lettersControl.CurrentLetters[_messageIndex]);
        }

        /// <summary>
        /// Deletes current letter.
        /// </summary>
        private void OnDeleteMessageExecute(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
        {
            _lettersControl.DeleteLetter(_messageControl.CurrentLetterVm);
            DataPresenter.Content = _lettersControl;
        }

        /// <summary>
        /// Show control with current letter
        /// </summary>
        private void LettersControlOnMessageClicked(LetterVm letterVm)
        {
            _messageIndex = _lettersControl.CurrentLetters.IndexOf(letterVm);
            _messageControl.PreviousButton.IsEnabled = _messageIndex != 0;
            _messageControl.NextButton.IsEnabled = _messageIndex != (_lettersControl.CurrentLetters.Count - 1);

            _messageControl.Load(letterVm);
            DataPresenter.Content = _messageControl;
        }

        /// <summary>
        /// Show control with current letter
        /// </summary>
        private void BalloonOnReadLetterOnClick(LetterVm letterVm)
        {
            if (WindowState == WindowState.Minimized)
            {
                Show();
                WindowState = WindowState.Normal;
            }

            _messageControl.PreviousButton.IsEnabled = false;
            _messageControl.NextButton.IsEnabled = false;

            _messageControl.Load(letterVm);
            DataPresenter.Content = _messageControl;
        }

        #endregion //End Interface events

        #region Letters events.

        /// <summary>
        /// Updates the interface and shows a balloon when sending emails.
        /// </summary>
        /// <param name="letterVm"></param>
        private void MailsControllerOnLetterSended(LetterVm letterVm)
        {
            UpdateLettersList(letterVm.RuleId);
            if (Settings.Default.ShowNotifications)
                ShowQmBalloon(letterVm);
        }

        /// <summary>
        /// Updates the interface and shows a balloon when an error sending the letter.
        /// </summary>
        /// <param name="letterVm"></param>
        private void MailsControllerOnLetterNotSended(LetterVm letterVm)
        {
            UpdateLettersList(letterVm.RuleId);
            if (Settings.Default.ShowNotifications)
                ShowQmBalloon(letterVm);
        }

        /// <summary>
        /// Updates the interface and shows a balloon when receiving emails.
        /// </summary>
        private void MailsControllerOnLetterReceived(LetterVm letterVm)
        {
            UpdateLettersList(letterVm.RuleId);
            if (Settings.Default.ShowNotifications)
                ShowQmBalloon(letterVm);
        }

        /// <summary>
        /// Updates the list of letters at the event.
        /// </summary>
        private void UpdateLettersList(long ruleId)
        {
            Dispatcher.Invoke((MethodInvoker)delegate
            {
                var selectedRule = MainRulesControl.RulesTreeView.SelectedItem as RuleVm;
                if (selectedRule != null)
                {
                    if (ruleId == selectedRule.Id
                        && Equals(DataPresenter.Content, _lettersControl))
                    {
                        _lettersControl.Load(selectedRule.Id);
                    }
                }
            });
        }

        /// <summary>
        /// Shows a balloon with the letter.
        /// </summary>
        private void ShowQmBalloon(LetterVm letterVm)
        {
            Dispatcher.Invoke((MethodInvoker)delegate
            {
                var qmBalloon = new QmBalloon(letterVm);
                qmBalloon.ReadLetterOnClick += BalloonOnReadLetterOnClick;
                QmNotifyIcon.ShowCustomBalloon(qmBalloon, PopupAnimation.Slide, 5000);     //show balloon and close it after 5 seconds
            });
        }

        #endregion //End Letters events.

        #region Tray events

        /// <summary>
        /// Shows a window when you double-click on the tray icon.
        /// </summary>
        private void QmNotifyIcon_OnTrayMouseDoubleClick(object sender, RoutedEventArgs e)
        {
            Show();
            WindowState = WindowState.Normal;
        }

        /// <summary>
        /// Disabled menu items.
        /// </summary>
        private void ContextMenu_OnOpened(object sender, RoutedEventArgs e)
        {
            HideMenuItem.IsEnabled = WindowState != WindowState.Minimized;
            ShowMenuItem.IsEnabled = WindowState == WindowState.Minimized;
        }

        /// <summary>
        /// Shows the window.
        /// </summary>
        private void ShowMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            Show();
            WindowState = WindowState.Normal;
        }

        /// <summary>
        /// Hide the window.
        /// </summary>
        private void HideMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// Exit the program.
        /// </summary>
        private void ExitMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            // ReSharper disable once RedundantThisQualifier
            this.Close();
        }

        #endregion
    }
}